import { createApp } from './main'
import { renderToString } from 'vue/server-renderer'
import { basename } from 'path'
import { useIndexStore } from './store'

export async function render (url: string, manifest: any, ssrContent: {
  ip?: string
} = {}, prerender = false) {
  const { app, router, minipinia, pinia } = createApp()

  // set the router to the desired URL before rendering
  await router.push(url)
  await router.isReady()
  const store = useIndexStore()
  // 设置 ip
  if (ssrContent.ip) {
    store.setIp(ssrContent.ip)
  }

  const to = router.currentRoute
  const matchedRoute = to.value.matched
  if (to.value.matched.length > 0 && !prerender) {
    const matchedComponents: any = []
    matchedRoute.forEach((route) => {
      matchedComponents.push(...Object.values(route.components))
    })
    const asyncDataFuncs = matchedComponents.map((component: any) => {
      const asyncData = component.asyncData || null
      if (asyncData) {
        const config = {
          store: pinia,
          route: to
        }
        return asyncData(config)
      }
      return undefined
    })
    // 请求页面级别组件数据，异步需等待
    await Promise.all(asyncDataFuncs)
  }
  // passing SSR context object which will be available via useSSRContext()
  // @vitejs/plugin-vue injects code into a component's setup() that registers
  // itself on ctx.modules. After the render, ctx.modules would contain all the
  // components that have been instantiated during this render call.
  const ctx: any = {}
  const html = await renderToString(app, ctx)

  // the SSR manifest generated by Vite contains module -> chunk/asset mapping
  // which we can then use to determine what files need to be preloaded for this
  // request.
  const metaInfo = router.currentRoute.value.meta.metaInfo || {}
  const preloadLinks = renderPreloadLinks(ctx.modules, manifest)
  return [html, preloadLinks, metaInfo, minipinia, pinia]
}

function renderPreloadLinks (modules: any, manifest: any) {
  let links = ''
  const seen = new Set()
  modules.forEach((id: string) => {
    const files = manifest[id]
    if (files) {
      files.forEach((file: string) => {
        if (!seen.has(file)) {
          seen.add(file)
          const filename = basename(file)
          if (manifest[filename]) {
            for (const depFile of manifest[filename]) {
              links += renderPreloadLink(depFile)
              seen.add(depFile)
            }
          }
          links += renderPreloadLink(file)
        }
      })
    }
  })
  return links
}

function renderPreloadLink (file: string) {
  console.log(file, 'file')
  if (file.endsWith('.js')) {
    return `<link rel="modulepreload" crossorigin href="${file}">`
  } else if (file.endsWith('.css')) {
    return `<link rel="stylesheet" href="${file}">`
  } else if (file.endsWith('.woff')) {
    return ` <link rel="preload" href="${file}" as="font" type="font/woff" crossorigin>`
  } else if (file.endsWith('.woff2')) {
    return ` <link rel="preload" href="${file}" as="font" type="font/woff2" crossorigin>`
  } else if (file.endsWith('.gif')) {
    return ` <link rel="preload" href="${file}" as="image" type="image/gif">`
  } else if (file.endsWith('.jpg') || file.endsWith('.jpeg')) {
    return ` <link rel="preload" href="${file}" as="image" type="image/jpeg">`
  } else if (file.endsWith('.png')) {
    return ` <link rel="preload" href="${file}" as="image" type="image/png">`
  } else {
    // TODO
    return ''
  }
}
